/** 应用程序全局配置
 * @file config.hpp
 * @author Kiven Lee
 * @version 1.0
 * @date 2021-08-08
 *
 * @copyright Copyright Kivensoft (c) 2021
 *
 */
#pragma once

#include <cstdio>
#include "klib_http/server.hpp"
#include "klib_http/jwt.hpp"
#include "api.hpp"
#include "session_data.hpp"
#include "dbcache.hpp"

namespace ai {
    namespace app {

        using namespace klib;
        using namespace klib::http;
        using std::string;
        using std::string_view;

        namespace _detail {

            // 由命令行参数进行初始化的变量
            inline bool                     _debug;             // 调试模式标志
            inline string                   _listen;            // 监听地址和端口
            inline string                   _work;              // 应用程序工作目录
            inline string                   _shutdown_pass;     // 远程关闭应用口令

            // 应用程序常量
            constexpr string_view           _jwt_iss            = "accinfo";                // jwt发布者
            constexpr string_view           _jwt_key            = "cn.kivensoft.accinfo";   // jwt秘钥
            constexpr uint32_t              _jwt_exp_minutes    = 20;                       // jwt过期时间
            constexpr uint32_t              _db_exp_minutes     = 3;                        // 数据库缓存过期时间

            // 由程序创建的单例
            inline datetime_t               _startup_time;      // 应用启动时间
            inline io_ctx_t*                _io_ctx;            // io_context
            inline server_t*                _pserver;           // 应用http服务
            inline ai_session_manager_t*    _sess_man;          // session管理类
            inline db_cache_t               _db_cache;          // 缓存

        } // namespace _detail


        /** 应用程序名称 */
        constexpr char name[] = "accinfo";
        /** 应用程序版本 */
        constexpr char ver[] = "1.1.202207";
        /** 应用程序描述 */
        constexpr char desc[] = "account information management service [http://www.kivensoft.cn]";

        /** api前缀 */
        constexpr char api_prefix[] = "/api";
        /** 静态资源路径 */
        constexpr char webroot[] = "/static";

        /** 调试标志 */
        inline bool debug() { return _detail::_debug; }
        /** http监听地址及端口 */
        inline const string& listen() { return _detail::_listen; }
        /** 应用程序工作目录 */
        inline const string& work() { return _detail::_work; }
        /** 远程关闭应用口令 */
        inline const string& shutdown_pass() { return _detail::_shutdown_pass; }

        /** 解析命令行, 返回false表示解析失败，程序应当要主动结束 */
        bool parse(int argc, char* const argv[]);
        /** 在控制台输出应用程序logo */
        void show_logo();

        /** 获取jwt令牌过期时间设置(分钟为单位) */
        inline uint32_t jwt_exp_minutes() { return _detail::_jwt_exp_minutes; }
        /** 获取数据库缓存过期时间设置(分钟为单位) */
        inline uint32_t db_exp_minutes() { return _detail::_db_exp_minutes; }

        // 应用程序运行时全局单例对象, 需要动态初始化
        inline datetime_t startup_time() { return _detail::_startup_time; }
        inline io_ctx_t& io_ctx() { return * _detail::_io_ctx; }
        inline server_t& http_server() { return *_detail::_pserver; }
        inline ai_session_manager_t& session_manager() { return *_detail::_sess_man; }

        inline server_t& set_server_name(server_t& svr) {
            char buf[sizeof(name) + sizeof(ver) + 2];
            std::snprintf(buf, sizeof(buf), "%s/%s", app::name, app::ver);
            return svr.set_name(buf);
        }

        /** 初始化全局变量 */
        inline void init(io_ctx_t& io_ctx, server_t& svr, ai_session_manager_t& sess_man) {
            using namespace _detail;
            _io_ctx         = &io_ctx;
            _pserver        = &svr;
            _sess_man       = &sess_man;
            _db_cache.expire_time(_jwt_exp_minutes * 60);
            _db_cache.db_expire_time(_db_exp_minutes * 60);
        }

        /** 生成jwt令牌
         *
         * @param output 输出对象
         * @return size_t 写入字节数
         */
        template<typename FN>
        inline size_t jwt_encode(bstring_t& output, const std::string_view& user, uint64_t sid) {
            assert(user.size());
            json::writer_impl_t<255> jw;
            auto exp = std::time(nullptr) + _detail::_jwt_exp_minutes * 60;
            klib::jwt::make_payload(jw, _detail::_jwt_iss, exp, [&user, &sid] (json::writer_t& w) {
                w.kvs("user", user, "sid", sid);
            });
            return klib::jwt::encode(output, _detail::_jwt_key, jw);
        }

        /** 校验jwt
         *
         * @param output 输出对象
         * @param jwtstring jwt令牌
         * @return klib::jwt_t::decode_state_t
         */
        inline jwt::check_result_t jwt_decode(bstring_t& out, std::string_view jwtstring) {
            assert(jwtstring.size());
            return jwt::decode(out, jwtstring, _detail::_jwt_iss, _detail::_jwt_key);
        }

    } // namespace app
} // namespace ai